package comm_handler

import (
	"context"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/service-config/constant"
	"gitee.com/zaper/service-config/service/etcd"
	"gitee.com/zaper/service-config/service/model"
	"gitee.com/zaper/service-config/task"
	clientv3 "go.etcd.io/etcd/client/v3"
	"runtime/debug"
	"strings"
	"sync"
	"time"
)

var (
	ConfigTable = map[string]string{
		constant.ConfigName: "SoftWareConfig",
		constant.GaussDB:    "GaussDBConfig",
		constant.RedisDB:    "RedisDBConfig",
		constant.Other:      "OtherConfig",
	}
	mu sync.Mutex
)

func ChangeHandler(key string, configName string, serviceList []string, opts ...clientv3.OpOption) bool {
	defer func() {
		e := recover()
		if e != nil {
			logger.Warnf("ChangeHandler exception stack is %s,err is %v", debug.Stack(), e)
			return
		}
	}()
	configList := GetConfigValueList(key, opts...)
	if configList == nil {
		logger.Warnf("Get configValueList is null")
		return false
	}
	var cfgName string
	if configName != "" {
		cfgName = configName
	} else {
		cfgName = GetConfigName(key)
		if cfgName == "" {
			logger.Warnf("Get cfgName is empty")
			return false
		}
	}
	t := task.NewTask(cfgName, serviceList, configList)
	task.GetSchedule().SubmitTask(t)
	return true
}

func GetConfigValueList(key string, opts ...clientv3.OpOption) []model.ConfigKeyValue {
	cli := RetryClientEtcd(etcd.GetEtcdClient, 5)
	resp, err := cli.Get(context.Background(), key, opts...)
	if err != nil {
		logger.Errorf("Get config info fail")
		return nil
	}
	var configList []model.ConfigKeyValue
	for _, kv := range resp.Kvs {
		config := model.ConfigKeyValue{
			Key:   GetConfigName(string(kv.Key)),
			Value: string(kv.Value),
		}
		configList = append(configList, config)
	}
	return configList
}

func GetConfigName(key string) string {
	subKeyArr := strings.Split(key, "/")
	var length = len(subKeyArr)
	// "/SoftWareConfig/Other" 路径下第三段是配置分类，第二段则是全量配置，如果不在配置表里面，则忽略变更
	if length != 2 && length != 3 {
		return ""
	}
	configNameKey := subKeyArr[length-1]
	configName, ok := ConfigTable[configNameKey]
	if !ok {
		return ""
	}
	return configName
}

func RetryClientEtcd(function func() (*clientv3.Client, error), delay int64) *clientv3.Client {
	for {
		cli, _ := function()
		if cli != nil {
			return cli
		}
		time.Sleep(time.Duration(delay) * time.Second)
	}
}
